This document describes the design of the plug-in system for BakaSub, version 1.0 of that system. Any plugin written for BakaSub must conform to this interface in order to be used with the program.
This document is PRELIMINARY and WILL change before even the first really implemented version. This is NOT a BakaSub plug-in development bible.. it's a guideline for how the plug-in system will be developed =). It's more for me than for anyone else at this point.
Basic Outline
-------------
A plug-in for BakaSub is basically a dynamically loaded library, whatever that implies for the given system. For Linux that would be a dlopen() .so object; for Windows it might a DLL file. In any case, the dynamically loadable module systems for basically all modern OS's support dynamic symbol resolution (resolving symbols from the host executable) and retrieving addresses by name (usually, for a function).
BakaSub deals only with plain vanilla ANSI-C functions. Even though this is the case, C++ is actually used in the execution of the plugin; because of differences between C++ compilers, libraries, and optimizations, it is not reccommended that plug-ins be mixed between compiles of BakaSub. This unfortunate tendancy of binary incompatability is not my fault. It's the result of a lack of concern for binary compatability in the Linux world due to the wide availability of source code and the (false) assumption that everyone knows how to compile it and wants to. With a _great_ deal of added complexity and hassle I could make it both platform and compiler independant; however, I don't think this is worth the effort. I did it once for a game I was working on and it's not a joy ride =). Binary compatability is unlikely to work in other environments either because of a lack of a standard for name mangling and such in ANSI C++. This may have changed since the writing of this document; your experiences will vary.
Every plug-in must provide three main functions. The first two are very straightforward, module_init, and module_shutdown. These are called at load and unload time, respectively, and their purposes are obvious; there is a little subtlety to each that is described below, however. The third, module_object, returns an allocated object. This object may be allocated inside the module or with the 'new' call, but the latter is definitely recommended due to quirks in object loaders for static initializers. The returned object will be a subclass of some type of supported Plugin_* class, and implement the interface of that class sufficient for operation. For example, a file loader should implement the load_script method; a complete file implementation should implement save_script as well, along with any other methods. A failure to implement a method will present the user with a "function not supported" error when they try to use it rather than crash or something equally ungraceful.
Operations of the individual module types is specific to that module type, so it won't be discussed at this point.
Specifics of the module interface
---------------------------------
For now, some quick function definitions:
int module_init();
This function is called during plug-in load. If it returns zero, then all is well. If it returns a positive integer, then the module load failed and the user has been informed of this fact. If it returns a negative integer, then the module load failed and the user has not been informed.
int module_shutdown();
Called during plug-in unload. A zero return means that it's ok to go ahead and deallocate the module; all shutdown is completed. A positive return value means that some resource within the module is still in use in the main program, and it can't be deallocated yet. A negative return value means that some other shutdown error occured.
Note for FYI sake -- a module doesn't have to implement any of those return codes except 0; they are just there for future usage.
Plugin_Base* module_object();
Returns a pointer to a new object that was derived from Plugin_Base. The object should implement all of the basic functionality of Plugin_Base and any additional methods for the type of plug-in that it is.
The Plugin_Base class
---------------------
The Plugin_Base class is the most generic object that can be dealt with in the plug-in system. Therefore it's not terribly useful to actually use one of these. What will really happen is that further on it will get casted to another type that has more functionality once the plug-in system knows what it is. All of this info is in Plugin_Base.h in the plugins tree of the BakaSub source; an overview is included here for info purposes.
virtual unsigned long version() { return 0x0000; }
};
In this case, your derived name() should return a human-readable string in the form of a bstring object describing what the module is. This should be fairly descriptive but not overly so; if a module listing is presented to the user, it will be catagorized by system. The derived system() should return a bstring describing the BakaSub subsystem the module pertains to. "none" is a catchall that means that it doesn't have a particular subsystem. The example NULL plug-in works this way, as would a plug-in that is meant to hook into an object somewhere in the main BakaSub object heirchy (not recommended, but possible). The result of system() will determine if a more specific plug-in handler applies, and thus, if a more specific Plugin_* class applies.
Here are the currently supported systems:
"none" -- Nothing more to be done
"script-file" -- Implements the Plugin_ScriptFile interface for loading and saving scripts
"render-engine" -- Implements the Plugin_RenderEngine interface for rendering output; this may implement either or both of the preview and final output engines. Note that this interface and system is completely seperate from the video acquisition system.
"compiler" -- Implements the Plugin_Compiler interface for converting script lines into binary usable C++ objects for use internally in BakaSub; it may also provide syntax highlighting for a script line style in the future. Writing one of these will let you, e.g., use JacoSub scripts natively inside BakaSub.
"video" -- Implements the Plugin_Video interface for video acquisition and output; this may implement either or both of the input and output methods.
"frame-control" -- Implements the Plugin_FrameControl interface for frame change control, which generally is designed to control an external device like an LD player to sync with the frame the user has selected in the GUI (or during playback).
More info about each of these follows below.
version() returns the version code for which this plug-in will work. BakaSub versions work on a three-layer system: major, minor, and miniscule. Plug-in compatability is guaranteed between miniscule version number changes; minor changes may cause things to work a bit differently but should still be ok; major changes will probably render a plug-in totally incompatable.
For proper usage of the app_shell member, see the other BakaSub sources and/or development info (if there is any =^). set_app_shell will generally be called by the plug-in handler for the script-file system; you shouldn't need to override this unless you want to do something funky.
compiler() returns a string that determines what kind of Plugin_Compiler objects this works with. See below for more info on this.
handles() returns true or false depending on whether you can handle a particular file extension. The extension will be passed by itself, e.g., "ssa".
load() and save() are pretty self-explanatory. They work using the internal representation of script files. Generally the generated script lines should be standard BakaSub style (which closely mimicks SSA style), which is referred to under compiler() as "bakasub". However, you can have it return other things like JacoSub lines if you provide a corresponding "compiler" plug-in.
This works more closely with the internal implementation structures of BakaSub, so it is tied more closely to a specific version of the program. Minor version changes may break binary plug-ins but they should work after a recompile. Major version changes may break binary plug-ins to the point of needing a port (with varying amounts of work).
See RenderEngine.h in the main BakaSub source tree for more info on this type of plug-in.
Plugin_Compiler
---------------
This will work like Plugin_RenderEngine but the interface isn't completely decided yet.
Plugin_Video
------------
This plug-in will work almost exclusively with bitmap data. Therefore, it will need some endian work in some cases. It will also need to be adaptable to different bit depths.
For chromakey overlay-style systems, the video buffer interfaced with the rendering system should return a buffer filled with the neccessary key color. This will be used as a background and drawn over when subtitles are rendered. For capture-style systems, an actual frame of video data should be returned. A size will be requested (so it will work with the preview).
Plugin_FrameControl
-------------------
Tied to small elements of the user interface. It will accept change-frame commands from the user dragging the frame slider or selecting a new script row; and it will also be able to issue frame change commands from the user jogging forward or backward in the video source.